#ifndef _YEP_ENGINE_SCENE2D_HPP
#define _YEP_ENGINE_SCENE2D_HPP

#include "../common.hpp"
#include "../core.hpp"
#include <list>

namespace yep
{
    class Entity; // Foward
    class FrameHandler; // Foward
    class DrawHandler; // Foward
    class CollisionHandler; // Foward
    class KeyboardHandler; // Foward
    class MouseHandler; // Foward
    /**
     * @brief A complete Scene implementation.
     *
     * It contains all basics elements to do a game, without extent it.
     *  Any possibly game object (such Actors, Tilesmaps, BGs) could be
     *  added here, using the corArea handlers.
     *
     * We sugest the following idiom to create a game object:
     *  - Have a scene* in your game object. You can pass it from constructor
     *     or setter or both.
     *  - Always implements a SceneHandler to check if the object is on the scene
     *     where it think it is and to have a chance to clean (and maybe delete
     *     itself) when the scene ends.
     **/
    class Scene2d: public Scene
    {
    public:
        /**
         * @brief Creates a 2dScene
         **/
        Scene2d();

        /**
         * @brief Destructor
         **/
        ~Scene2d();

        /**
         * @see Scene::setup().
         *
         * This implementation only calls fireCreate() and fireSceneBegin().
         *  if it is the first scene it also calls fireGameBegin(). So. if you
         *  override this. you must do one of following alternatives:
         * -# Call Scene2d::setup() after your last object insertion;
         * -# Put the following piece of code after your last object insertion:
         *   @code
         *    fireSetup(!game.running())
         *   @endcode
         **/
        virtual void setup(Game &game);

        /**
         * @see Scene::cleanup().
         *
         * This implementation only calls fireDestroy() and fireSceneEnd().
         *  if it is the last scene it also calls fireGameEnd(). So. if you
         *  override this, you must do one of following alternatives:
         * -# Call Scene2d::cleanup() after your last object access;
         * -# Put the following piece of code after your last object access:
         *   @code
         *      fireCleanup(!game.running());
         *   @endcode
         *
         * Notice that you don't need erasing any object, it assumes that all
         *  SceneHandlers have to be erased and erase it.
         **/
        virtual void cleanup(Game &game);

        /**
         * @see Scene::logic().
         **/
        void logic(Game &game);

        /**
         * @see Scene::draw().
         **/
        void draw(Game &game);

        /**
         * @brief Adds a new Scene Handler.
         **/
        void add(Entity &handler);

        /**
         * @brief Returns wheter it has the given Scene Handler
         **/
        bool has(Entity &handler);

        /**
         * @brief Removes the Scene Handler
         **/
        void remove(Entity &handler);

        /**
         * @brief Adds a new Frame Handler.
         **/
        void handleFrame(FrameHandler &handler);

        /**
         * @brief Returns wheter it has the given Frame Handler
         **/
        bool isHandlingFrame(FrameHandler &handler);

        /**
         * @brief Removes the Frame Handler
         **/
        void unhandleFrame(FrameHandler &handler);

        /**
         * @brief Adds a new Draw Handler.
         **/
        void handleDraw(DrawHandler &handler);

        /**
         * @brief Returns wheter it has the given Draw Handler
         **/
        bool isHandlingDraw(DrawHandler &handler);

        /**
         * @brief Removes the Draw Handler
         **/
        void unhandleDraw(DrawHandler &handler);

        /**
         * @brief Adds a new Collision Handler.
         **/
        void handleCollision(CollisionHandler &handler);

        /**
         * @brief Returns wheter it has the given Collision Handler
         **/
        bool isHandlingCollision(CollisionHandler &handler);

        /**
         * @brief Removes the Collision Handler
         **/
        void unhandleCollision(CollisionHandler &handler);

        /**
         * @brief Adds a new Keyboard Handler.
         **/
        void handleKeyboard(KeyboardHandler &handler);

        /**
         * @brief Returns wheter it has the given Keyboard Handler
         **/
        bool isHandlingKeyboard(KeyboardHandler &handler);

        /**
         * @brief Removes the Keyboard Handler
         **/
        void unhandleKeyboard(KeyboardHandler &handler);

        /**
         * @brief Adds a new Mouse Handler.
         **/
        void handleMouse(MouseHandler &handler);

        /**
         * @brief Returns wheter it has the given Mouse Handler
         **/
        bool isHandlingMouse(MouseHandler &handler);

        /**
         * @brief Removes the Mouse Handler
         **/
        void unhandleMouse(MouseHandler &handler);
    protected:
        /**
         * @brief Initializes all the SceneHandlers
         **/
        void fireSetup(Game &game, bool isFirstScene);

        /**
         * @brief Destroy all SceneHandlers
         **/
        void fireCleanup(Game &game, bool isLastScene);

    private:
        list<Entity*> _sceneHandlers;
        list<Entity*> _unbornHandlers; ///< @brief Not created handlers.
        list<Entity*> _dyingHandlers;  ///< @brief Almost dead handlers.
        list<FrameHandler*> _frameHandlers;
        list<DrawHandler*> _drawHandlers;
        list<CollisionHandler*> _collisionHandlers;
        list<KeyboardHandler*> _keyboardHandlers;
        list<MouseHandler*> _mouseHandlers;
    };

}

#endif // _YEP_ENGINE_SCENE2D_HPP

